#pragma once

#include <inttypes.h>
#include <stdint.h>

#include "luster_alloc.hh"
#include "luster_log.hh"

#define luster_declare_dynarr(M_arrname, M_ty) \
	typedef struct M_arrname { \
		M_ty *elements; \
		uintptr_t len; \
		uintptr_t cap; \
	} M_arrname##_t; \
\
	M_ty *M_arrname##_append(M_arrname##_t *ls); \
	void M_arrname##_reserve(M_arrname##_t *ls, uintptr_t cap); \
	void M_arrname##_deinit(M_arrname##_t *ls)

enum { DYNARR_CAP_INIT = 4 };

static inline uintptr_t dynarr_cap_grow(uintptr_t cap) {
	return cap * 3 / 2;
}

// 将扩动态数组的容量。
//
// - 如果 newcap 为 0，则扩张当 *cap 的 1.5 倍。
// - 如果 newcap 不为 0，则扩张当容量至少 newcap。
static inline void dynarr_enlarge_(void **elements, uintptr_t element_size,
	uintptr_t *cap, uintptr_t newcap) {
	if (newcap == 0) {
		(*cap) = (*cap) == 0 ? DYNARR_CAP_INIT : dynarr_cap_grow(*cap);
	} else {
		if ((*cap) == 0) {
			*cap = DYNARR_CAP_INIT;
		}

		while ((*cap) < newcap) {
			*cap = dynarr_cap_grow(*cap);
		}
	}

	*elements = luster::reallocate(*elements, element_size * (*cap));

	logprint(LOG_DEBUG,
		"enlarge size to %" PRIuPTR " x %" PRIuPTR " (%" PRIuPTR
		" bytes)",
		*cap, element_size, (*cap) * element_size);
}

#define luster_define_dynarr(M_arrname, M_ty) \
	M_ty *M_arrname##_append(M_arrname##_t *ls) { \
		if (ls->len >= ls->cap) { \
			dynarr_enlarge_((void **)&ls->elements, sizeof(M_ty), \
				&ls->cap, 0); \
		} \
\
		M_ty *r = ls->elements + ls->len; \
		ls->len += 1; \
		return r; \
	} \
\
	void M_arrname##_reserve(M_arrname##_t *ls, uintptr_t cap) { \
		if (ls->cap <= cap) { \
			dynarr_enlarge_((void **)&ls->elements, sizeof(M_ty), \
				&ls->cap, cap); \
		} \
	} \
\
	void M_arrname##_deinit(M_arrname##_t *ls) { \
		if (ls->cap == 0) \
			return; \
		luster::deallocate(ls->elements); \
		ls->cap = 0; \
		ls->len = 0; \
	} \
\
	enum { DYNARR_##M_arrname = 0 }

luster_declare_dynarr(usize_lst, uintptr_t);
